﻿/********************************** (C) COPYRIGHT *******************************
* File Name          : CDCx2.C
* Author             : qianfan Zhao
* Version            : V1.0
* Date               : 2021/05/27
* Description        : CH552 virtual two channel CDC serial port
*******************************************************************************/
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include <ch554.h>
#include <ch554_usb.h>
#include <debug.h>

/* 红灯定义在P3.3, 绿灯定义在P3.4, 拉低引脚能够点亮LED */
#define LED_RED					3
#define LED_GREEN				4
#define DEFAULT_LED_ON_TIMEOUT			100

#ifndef CDC_LOOPBACK
void set_config_uart0(__xdata uint8_t *acm_line_code)
{
	uint32_t baud = 0;

	baud |= acm_line_code[3];
	baud <<= 8;
	baud |= acm_line_code[2];
	baud <<= 8;
	baud |= acm_line_code[1];
	baud <<= 8;
	baud |= acm_line_code[0];

	TH1 = 256 - FREQ_SYS / baud / 16;
}

void set_config_uart1(__xdata uint8_t *acm_line_code)
{
	uint32_t baud = 0;

	baud |= acm_line_code[3];
	baud <<= 8;
	baud |= acm_line_code[2];
	baud <<= 8;
	baud |= acm_line_code[1];
	baud <<= 8;
	baud |= acm_line_code[0];

	SBAUD1 = 256 - FREQ_SYS / 16 / baud;
}
#endif

/*
 * Endpoint configuration:
 * CDC0: bulk_in(0x82), bulk_out(0x02), int_in(0x81)
 * CDC1: bulk_in(0x83), bulk_out(0x03), int_in(0x04)
 */
__xdata __at (0x0000) uint8_t  Ep0Buffer[DEFAULT_ENDP0_SIZE];
__xdata __at (0x0040) uint8_t  Ep1Buffer[8];
__xdata __at (0x0080) uint8_t  Ep2Buffer[2 * MAX_PACKET_SIZE];
__xdata __at (0x0100) uint8_t  Ep3Buffer[2 * MAX_PACKET_SIZE];
__xdata __at (0x0180) uint8_t  Ep4Buffer[8];

#define  SET_LINE_CODING                0X20            // Configures DTE rate, stop-bits, parity, and number-of-character
#define  GET_LINE_CODING                0X21            // This request allows the host to find out the currently configured line coding.
#define  SET_CONTROL_LINE_STATE         0X22            // This request generates RS-232/V.24 style control signals.

/*
 * usb device descriptors are generated by: https://xtoolbox.gitee.io/teenydt/
 * return Device {
 *    strManufacturer = "dog2nd_Zhao",
 *    strProduct = "USB CDCx2",
 *    strSerial =  "USB123456",
 *    idVendor = 0x1a86,
 *    idProduct = 0x5723,
 *    prefix = "CDC_ACM2",
 *    Config {
 *        CDC_ACM{
 *            EndPoint(IN(1), Interrupt, 8),
 *            EndPoint(IN(2), Bulk, 64),
 *            EndPoint(OUT(2), Bulk, 64),
 *        },
 *        CDC_ACM{
 *            EndPoint(IN(4),  Interrupt, 8),
 *            EndPoint(IN(3), Bulk, 64),
 *            EndPoint(OUT(3),  Bulk, 64),
 *        },
 *   }
 *}
*/

#define USB_DEVICE_DESCRIPTOR_TYPE              0x01
#define USB_CONFIGURATION_DESCRIPTOR_TYPE       0x02
#define USB_STRING_DESCRIPTOR_TYPE              0x03
#define USB_INTERFACE_DESCRIPTOR_TYPE           0x04
#define USB_ENDPOINT_DESCRIPTOR_TYPE            0x05
#define USB_IAD_DESCRIPTOR_TYPE                 0x0B
#define USB_HUB_DESCRIPTOR_TYPE                 0x29
#define USB_HID_DESCRIPTOR_TYPE                 0x21
#define USB_REPORT_DESCRIPTOR_TYPE              0x22
#define USB_DESC_TYPE_REPORT                    0x22
#define USB_FUCNTION_DESCRIPTOR_TYPE            0x24

__code const uint8_t CDC_ACM2_DeviceDescriptor [18] = {
  ///////////////////////////////////////
  /// device descriptor
  ///////////////////////////////////////
  0x12,                                             /* bLength */
  USB_DEVICE_DESCRIPTOR_TYPE,                       /* bDescriptorType */
  0x00, 0x02,                                       /* bcdUSB */
  0xef,                                             /* bDeviceClass */
  0x02,                                             /* bDeviceSubClass */
  0x01,                                             /* bDeviceProtocol */
  DEFAULT_ENDP0_SIZE,                               /* bMaxPacketSize */
  0x86, 0x1a,                                       /* idVendor */
  0x23, 0x57,                                       /* idProduct */
  0x00, 0x01,                                       /* bcdDevice */
  0x01,                                             /* iManufacturer */
  0x02,                                             /* iProduct */
  0x03,                                             /* iSerial */
  0x01,                                             /* bNumConfigurations */
};

__code const uint8_t CDC_ACM2_ConfigDescriptor1 [141] = {
  ///////////////////////////////////////
  /// config descriptor
  ///////////////////////////////////////
  0x09,                                             /* bLength */
  USB_CONFIGURATION_DESCRIPTOR_TYPE,                /* bDescriptorType */
  0x8d, 0x00,                                       /* wTotalLength */
  0x04,                                             /* bNumInterfaces */
  0x01,                                             /* bConfigurationValue */
  0x00,                                             /* iConfiguration */
  0x80,                                             /* bmAttributes */
  0x64,                                             /* bMaxPower */

  ///////////////////////////////////////
  /// interface association descriptor
  ///////////////////////////////////////
  0x08,                                             /* bLength */
  USB_IAD_DESCRIPTOR_TYPE,                          /* bDescriptorType */
  0x00,                                             /* bFirstInterface */
  0x02,                                             /* bInterfaceCount */
  0x02,                                             /* bFunctionClass */
  0x02,                                             /* bFunctionSubClass */
  0x01,                                             /* bFunctionProtocol */
  0x00,                                             /* iFunction */

  ///////////////////////////////////////
  /// interface descriptor
  ///////////////////////////////////////
  0x09,                                             /* bLength */
  USB_INTERFACE_DESCRIPTOR_TYPE,                    /* bDescriptorType */
  0x00,                                             /* bInterfaceNumber */
  0x00,                                             /* bAlternateSetting */
  0x01,                                             /* bNumEndpoints */
  0x02,                                             /* bInterfaceClass */
  0x02,                                             /* bInterfaceSubClass */
  0x01,                                             /* bInterfaceProtocol */
  0x00,                                             /* iInterface */

  ///////////////////////////////////////
  /// cdc acm header descriptor
  ///////////////////////////////////////
  0x05,                                             /* bLength */
  0x24,                                             /* bDescriptorType */
  0x00,                                             /* bDescriptorSubtype */
  0x10, 0x01,                                       /* bcdCDC */

  ///////////////////////////////////////
  /// cdc acm call management descriptor
  ///////////////////////////////////////
  0x05,                                             /* bLength */
  0x24,                                             /* bDescriptorType */
  0x01,                                             /* bDescriptorSubtype */
  0x00,                                             /* bmCapabilities */
  0x01,                                             /* bDataInterface */

  ///////////////////////////////////////
  /// cdc acm descriptor
  ///////////////////////////////////////
  0x04,                                             /* bLength */
  0x24,                                             /* bDescriptorType */
  0x02,                                             /* bDescriptorSubtype */
  0x02,                                             /* bmCapabilities */

  ///////////////////////////////////////
  /// cdc acm union descriptor
  ///////////////////////////////////////
  0x05,                                             /* bLength */
  0x24,                                             /* bDescriptorType */
  0x06,                                             /* bDescriptorSubtype */
  0x00,                                             /* bMasterInterface */
  0x01,                                             /* bSlaveInterface0 */

  ///////////////////////////////////////
  /// endpoint descriptor
  ///////////////////////////////////////
  0x07,                                             /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,                     /* bDescriptorType */
  0x81,                                             /* bEndpointAddress */
  0x03,                                             /* bmAttributes */
  0x08, 0x00,                                       /* wMaxPacketSize */
  0x01,                                             /* bInterval */

  ///////////////////////////////////////
  /// interface descriptor
  ///////////////////////////////////////
  0x09,                                             /* bLength */
  USB_INTERFACE_DESCRIPTOR_TYPE,                    /* bDescriptorType */
  0x01,                                             /* bInterfaceNumber */
  0x00,                                             /* bAlternateSetting */
  0x02,                                             /* bNumEndpoints */
  0x0a,                                             /* bInterfaceClass */
  0x00,                                             /* bInterfaceSubClass */
  0x00,                                             /* bInterfaceProtocol */
  0x00,                                             /* iInterface */

  ///////////////////////////////////////
  /// endpoint descriptor
  ///////////////////////////////////////
  0x07,                                             /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,                     /* bDescriptorType */
  0x82,                                             /* bEndpointAddress */
  0x02,                                             /* bmAttributes */
  0x40, 0x00,                                       /* wMaxPacketSize */
  0x01,                                             /* bInterval */

  ///////////////////////////////////////
  /// endpoint descriptor
  ///////////////////////////////////////
  0x07,                                             /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,                     /* bDescriptorType */
  0x02,                                             /* bEndpointAddress */
  0x02,                                             /* bmAttributes */
  0x40, 0x00,                                       /* wMaxPacketSize */
  0x01,                                             /* bInterval */

  ///////////////////////////////////////
  /// interface association descriptor
  ///////////////////////////////////////
  0x08,                                             /* bLength */
  USB_IAD_DESCRIPTOR_TYPE,                          /* bDescriptorType */
  0x02,                                             /* bFirstInterface */
  0x02,                                             /* bInterfaceCount */
  0x02,                                             /* bFunctionClass */
  0x02,                                             /* bFunctionSubClass */
  0x01,                                             /* bFunctionProtocol */
  0x00,                                             /* iFunction */

  ///////////////////////////////////////
  /// interface descriptor
  ///////////////////////////////////////
  0x09,                                             /* bLength */
  USB_INTERFACE_DESCRIPTOR_TYPE,                    /* bDescriptorType */
  0x02,                                             /* bInterfaceNumber */
  0x00,                                             /* bAlternateSetting */
  0x01,                                             /* bNumEndpoints */
  0x02,                                             /* bInterfaceClass */
  0x02,                                             /* bInterfaceSubClass */
  0x01,                                             /* bInterfaceProtocol */
  0x00,                                             /* iInterface */

  ///////////////////////////////////////
  /// cdc acm header descriptor
  ///////////////////////////////////////
  0x05,                                             /* bLength */
  0x24,                                             /* bDescriptorType */
  0x00,                                             /* bDescriptorSubtype */
  0x10, 0x01,                                       /* bcdCDC */

  ///////////////////////////////////////
  /// cdc acm call management descriptor
  ///////////////////////////////////////
  0x05,                                             /* bLength */
  0x24,                                             /* bDescriptorType */
  0x01,                                             /* bDescriptorSubtype */
  0x00,                                             /* bmCapabilities */
  0x01,                                             /* bDataInterface */

  ///////////////////////////////////////
  /// cdc acm descriptor
  ///////////////////////////////////////
  0x04,                                             /* bLength */
  0x24,                                             /* bDescriptorType */
  0x02,                                             /* bDescriptorSubtype */
  0x02,                                             /* bmCapabilities */

  ///////////////////////////////////////
  /// cdc acm union descriptor
  ///////////////////////////////////////
  0x05,                                             /* bLength */
  0x24,                                             /* bDescriptorType */
  0x06,                                             /* bDescriptorSubtype */
  0x02,                                             /* bMasterInterface */
  0x03,                                             /* bSlaveInterface0 */

  ///////////////////////////////////////
  /// endpoint descriptor
  ///////////////////////////////////////
  0x07,                                             /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,                     /* bDescriptorType */
  0x84,                                             /* bEndpointAddress */
  0x03,                                             /* bmAttributes */
  0x08, 0x00,                                       /* wMaxPacketSize */
  0x01,                                             /* bInterval */

  ///////////////////////////////////////
  /// interface descriptor
  ///////////////////////////////////////
  0x09,                                             /* bLength */
  USB_INTERFACE_DESCRIPTOR_TYPE,                    /* bDescriptorType */
  0x03,                                             /* bInterfaceNumber */
  0x00,                                             /* bAlternateSetting */
  0x02,                                             /* bNumEndpoints */
  0x0a,                                             /* bInterfaceClass */
  0x00,                                             /* bInterfaceSubClass */
  0x00,                                             /* bInterfaceProtocol */
  0x00,                                             /* iInterface */

  ///////////////////////////////////////
  /// endpoint descriptor
  ///////////////////////////////////////
  0x07,                                             /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,                     /* bDescriptorType */
  0x83,                                             /* bEndpointAddress */
  0x02,                                             /* bmAttributes */
  0x40, 0x00,                                       /* wMaxPacketSize */
  0x01,                                             /* bInterval */

  ///////////////////////////////////////
  /// endpoint descriptor
  ///////////////////////////////////////
  0x07,                                             /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,                     /* bDescriptorType */
  0x03,                                             /* bEndpointAddress */
  0x02,                                             /* bmAttributes */
  0x40, 0x00,                                       /* wMaxPacketSize */
  0x01,                                             /* bInterval */
};

__code const uint8_t CDC_ACM2_StringDescriptor0 [4] = {
  0x04,                                         /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,                   /* bDescriptorType */
  0x09, 0x04,                                   /* wLangID0 */
};

__code const uint8_t CDC_ACM2_StringDescriptor1 [24] = {
  0x18,                                             /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,                       /* bDescriptorType */
  'd', 0x00,                                        /* wcChar0 */
  'o', 0x00,                                        /* wcChar1 */
  'g', 0x00,                                        /* wcChar2 */
  '2', 0x00,                                        /* wcChar3 */
  'n', 0x00,                                        /* wcChar4 */
  'd', 0x00,                                        /* wcChar5 */
  '_', 0x00,                                        /* wcChar6 */
  'Z', 0x00,                                        /* wcChar7 */
  'h', 0x00,                                        /* wcChar8 */
  'a', 0x00,                                        /* wcChar9 */
  'o', 0x00,                                        /* wcChar10 */
};

__code const uint8_t CDC_ACM2_StringDescriptor2 [20] = {
  0x14,                                             /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,                       /* bDescriptorType */
  'U', 0x00,                                        /* wcChar0 */
  'S', 0x00,                                        /* wcChar1 */
  'B', 0x00,                                        /* wcChar2 */
  ' ', 0x00,                                        /* wcChar3 */
  'C', 0x00,                                        /* wcChar4 */
  'D', 0x00,                                        /* wcChar5 */
  'C', 0x00,                                        /* wcChar6 */
  'x', 0x00,                                        /* wcChar7 */
  '2', 0x00,                                        /* wcChar8 */
};

__code const uint8_t CDC_ACM2_StringDescriptor3 [20] = {
  0x14,                                             /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,                       /* bDescriptorType */
  'U', 0x00,                                        /* wcChar0 */
  'S', 0x00,                                        /* wcChar1 */
  'B', 0x00,                                        /* wcChar2 */
  '1', 0x00,                                        /* wcChar3 */
  '2', 0x00,                                        /* wcChar4 */
  '3', 0x00,                                        /* wcChar5 */
  '4', 0x00,                                        /* wcChar6 */
  '5', 0x00,                                        /* wcChar7 */
  '6', 0x00,                                        /* wcChar8 */
};

#ifndef CDC_LOOPBACK

#define UART_FIFO_SIZE			64
#define UART_FIFO_SIZE_MASK		(UART_FIFO_SIZE - 1)

struct uart_fifo {
	uint8_t			uart_fifo[UART_FIFO_SIZE];
	uint8_t			uart_fifo_w_idx, uart_fifo_r_idx;
};

static volatile __idata struct uart_fifo uart0 = {
	.uart_fifo_w_idx = 0,
	.uart_fifo_r_idx = 0,
};

static volatile __idata struct uart_fifo uart1 = {
	.uart_fifo_w_idx = 0,
	.uart_fifo_r_idx = 0,
};

#define uart_fifo_is_empty(uart)								\
	((uart)->uart_fifo_w_idx == (uart)->uart_fifo_r_idx)
#define uart_fifo_is_full(uart)									\
	((((uart)->uart_fifo_w_idx - (uart)->uart_fifo_r_idx) & UART_FIFO_SIZE_MASK) == UART_FIFO_SIZE_MASK)
#define uart_fifo_length(uart)									\
	(((uart)->uart_fifo_w_idx - (uart)->uart_fifo_r_idx) & UART_FIFO_SIZE_MASK)

#define uart_fifo_put(uart, b) do {								\
	if (!uart_fifo_is_full(uart)) {								\
		(uart)->uart_fifo[(uart)->uart_fifo_w_idx] = b;					\
		(uart)->uart_fifo_w_idx = ((uart)->uart_fifo_w_idx + 1) & UART_FIFO_SIZE_MASK;	\
	}											\
}while (0)

#define uart_fifo_get_without_check(uart, b) do {						\
	*(b) = (uart)->uart_fifo[(uart)->uart_fifo_r_idx];					\
	(uart)->uart_fifo_r_idx = ((uart)->uart_fifo_r_idx + 1) & UART_FIFO_SIZE_MASK;		\
} while (0)
#endif

struct cdc_device {
	uint8_t				line_coding[7];
	uint8_t				upload_busy;
	uint8_t				usb_rx_size;
	uint8_t				usb_fifo_idx;
	uint8_t				led;
	uint8_t				led_timeout;
#ifndef CDC_LOOPBACK
	__idata struct uart_fifo	*uart;
#endif
};

/* the default baud rate is 57600-8-N-1 */
static volatile __xdata struct cdc_device cdc0 = {
	.line_coding = { 0x00, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x08 },
	.upload_busy = 0,
	.usb_rx_size = 0,
	.usb_fifo_idx = 0,
	.led = LED_RED,
	.led_timeout = 0,
#ifndef CDC_LOOPBACK
	.uart = &uart0,
#endif
};

static volatile __xdata struct cdc_device cdc1 = {
	.line_coding = { 0x00, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x08 },
	.upload_busy = 0,
	.usb_rx_size = 0,
	.usb_fifo_idx = 0,
	.led = LED_GREEN,
	.led_timeout = 0,
#ifndef CDC_LOOPBACK
	.uart = &uart1,
#endif
};

void cdc_turn_on_led(__xdata struct cdc_device *cdc)
{
	if (cdc->led_timeout == 0) {
		P3 &= ~(1 << cdc->led);
		cdc->led_timeout = DEFAULT_LED_ON_TIMEOUT;
	}
}

void cdc_turn_off_led(__xdata struct cdc_device *cdc)
{
	P3 |= (1 << cdc->led);
	cdc->led_timeout = 0;
}

/*******************************************************************************
* Function Name  : USBDeviceCfg()
* Description    : USB device mode configuration
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void USBDeviceCfg()
{
	USB_CTRL = 0x00;						//Clear USB control register
	USB_CTRL &= ~bUC_HOST_MODE;					//This bit selects the device mode
	USB_CTRL |=  bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN;		//USB device and internal pull-up enable, automatically return to NAK before interrupt flag is cleared
	USB_DEV_AD = 0x00;						//Device address initialization
	USB_CTRL &= ~bUC_LOW_SPEED;
	UDEV_CTRL &= ~bUD_LOW_SPEED;					//Select full speed 12M mode, the default mode
	UDEV_CTRL = bUD_PD_DIS;						// Disable DP / DM pull-down resistor
	UDEV_CTRL |= bUD_PORT_EN;					//Enable physical port
}
/*******************************************************************************
* Function Name  : USBDeviceIntCfg()
* Description    : USB device mode interrupt initialization
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void USBDeviceIntCfg()
{
	USB_INT_EN |= bUIE_SUSPEND;					//Enable device suspend interrupt
	USB_INT_EN |= bUIE_TRANSFER;					//Enable USB transfer completion interrupt
	USB_INT_EN |= bUIE_BUS_RST;					//Enable device mode USB bus reset interrupt
	USB_INT_FG |= 0x1F;						//Clear interrupt flag
	IE_USB = 1;							//Enable USB interrupt
	EA = 1;								//Allow microcontroller interrupt
}
/*******************************************************************************
* Function Name  : USBDeviceEndPointCfg()
* Description    : USB device mode endpoint configuration, simulation compatible HID device, in addition to endpoint 0 control transmission, also includes endpoint 2 batch upload
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void USBDeviceEndPointCfg()
{
	UEP1_DMA = (uint16_t) Ep1Buffer;				//Endpoint 1 sends data transfer address
	UEP2_DMA = (uint16_t) Ep2Buffer;				//Endpoint 2 IN data transfer address
	UEP3_DMA = (uint16_t) Ep3Buffer;
	UEP2_3_MOD = 0xCC;						//Endpoint 2/3 single buffer transceiver enable
	UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK;	//Endpoint 2 automatically flips the synchronization flag, IN transaction returns NAK, OUT returns ACK
	UEP3_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK;

	UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK;			//Endpoint 1 automatically flips the synchronization flag, IN transaction returns NAK
	UEP4_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK;
	UEP0_DMA = (uint16_t) Ep0Buffer;				//Endpoint 0 data transfer address
	UEP4_1_MOD = 0x44;						//Endpoint 1 upload buffer;
	UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;			//Manual flip, OUT transaction returns ACK, IN transaction returns NAK
}

static volatile uint8_t usb_new_address = 0, usb_configuration = 0;
static const uint8_t *setup_transfing_point = NULL;
static volatile uint16_t setup_transfing_size = 0;
static volatile USB_SETUP_REQ usb_last_setup_req;

#define mark_ep0_nothing_upload() do {		\
	setup_transfing_point = NULL;		\
	setup_transfing_size = 0;		\
} while (0)

void usb_irq_reset_handler(void)
{
	UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
	UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK;
	UEP4_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK;
	UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK;
	UEP3_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK;
	USB_DEV_AD = 0x00;
	UIF_SUSPEND = 0;
	UIF_TRANSFER = 0;
	UIF_BUS_RST = 0;

	cdc0.upload_busy = 0;
	cdc0.usb_rx_size = 0;
	cdc1.upload_busy = 0;
	cdc1.usb_rx_size = 0;

	usb_configuration = 0;
}

void usb_irq_suspend_handler(void)
{
	UIF_SUSPEND = 0;
	if ( USB_MIS_ST & bUMS_SUSPEND ) {
		while ( XBUS_AUX & bUART0_TX ) {
			; //等待发送完成
		}
		SAFE_MOD = 0x55;
		SAFE_MOD = 0xAA;
		WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO | bWAK_RXD1_LO; //USB或者RXD0/1有信号时可被唤醒
		PCON |= PD; //睡眠
		SAFE_MOD = 0x55;
		SAFE_MOD = 0xAA;
		WAKE_CTRL = 0x00;
	}
}

void usb_irq_in_handler(uint8_t ep)
{
	int len;

	switch (ep) {
	case 1: /* CDC0 interrupt in, NAK */
		UEP1_T_LEN = 0;
		UEP1_CTRL = UEP1_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK;
		break;
	case 4: /* CDC1 interrupt in, NAK */
		UEP4_T_LEN = 0;
		UEP4_CTRL = UEP4_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK;
		break;

	case 2: /* CDC0 bulk in, NAK and clear busy flag */
		UEP2_T_LEN = 0;
		UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK;
		cdc0.upload_busy = 0;
		break;
	case 3: /* CDC1 bulk in, NAK and clear busy flag */
		UEP3_T_LEN = 0;
		UEP3_CTRL = UEP3_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK;
		cdc1.upload_busy = 0;
		break;

	case 0: /* 端点0分包传输 */
		switch(usb_last_setup_req.bRequest) {
		case USB_GET_DESCRIPTOR:
			len = setup_transfing_size;

			if (len == 0 && !setup_transfing_point) {
				/* nothing need sending, force ending setup transfer */
				UEP0_T_LEN = 0;
				UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
				break;
			} else if (len > DEFAULT_ENDP0_SIZE) {
				len = DEFAULT_ENDP0_SIZE;
			}

			memcpy(Ep0Buffer, setup_transfing_point, len);
			setup_transfing_point += len;
			setup_transfing_size -= len;
			if (len < DEFAULT_ENDP0_SIZE && setup_transfing_size == 0)
				setup_transfing_point = NULL;

			UEP0_T_LEN = len;
			UEP0_CTRL ^= bUEP_T_TOG;
			break;
		case USB_SET_ADDRESS:
			USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | usb_new_address;
			UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
			break;
		default:
			UEP0_T_LEN = 0;
			UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
			break;
		}
		break;
	}
}

void usb_irq_out_handler(uint8_t ep)
{
	__xdata struct cdc_device *cdc = NULL;

	if (U_TOG_OK) { /* 不同步的数据包将丢弃 */
		switch (ep) {
		case 2: /* CDC0 bulk out, save recved length and NAK */
			cdc0.usb_rx_size = USB_RX_LEN;
			UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_R_RES | UEP_R_RES_NAK;
			break;
		case 3: /* CDC1 bulk out */
			cdc1.usb_rx_size = USB_RX_LEN;
			UEP3_CTRL = UEP3_CTRL & ~ MASK_UEP_R_RES | UEP_R_RES_NAK;
			break;
		case 0:
			switch (usb_last_setup_req.bRequest) {
			case SET_LINE_CODING:
				if (usb_last_setup_req.wIndexL == 0) { /* interface 0 is CDC0 */
					cdc = &cdc0;
				#ifndef CDC_LOOPBACK
					set_config_uart0(Ep0Buffer);
				#endif
				} else if (usb_last_setup_req.wIndexL == 2) { /* interface 2 is CDC1 */
					cdc = &cdc1;
				#ifndef CDC_LOOPBACK
					set_config_uart1(Ep0Buffer);
				#endif
				}

				if (cdc) {
					memcpy(cdc->line_coding, Ep0Buffer, USB_RX_LEN);
					UEP0_T_LEN = 0;
					UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_ACK;
				} else {
					UEP0_T_LEN = 0;
					UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_NAK;
				}
				break;
			default:
				UEP0_T_LEN = 0;
				UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_NAK;
				break;
			}
			break;
		}
	}
}

int usb_get_descriptor_handler(uint8_t wValueH, uint8_t wValueL)
{
	#define response_descriptor(d) do {	\
		desc = d;			\
		sz_desc = sizeof(d);		\
	} while (0)
	const uint8_t *desc = NULL;
	int sz_desc = 0;

	switch (wValueH) {
	case 1: /* device descriptor */
		response_descriptor(CDC_ACM2_DeviceDescriptor);
		break;

	case 2: /* config descriptor */
		response_descriptor(CDC_ACM2_ConfigDescriptor1);
		break;

	case 3: /* string descriptor */
		switch (wValueL) {
		case 0:
			response_descriptor(CDC_ACM2_StringDescriptor0);
			break;
		case 1: /* iManufacturer */
			response_descriptor(CDC_ACM2_StringDescriptor1);
			break;
		case 2:  /* iProduct */
			response_descriptor(CDC_ACM2_StringDescriptor2);
			break;
		case 3: /* iSerial */
			response_descriptor(CDC_ACM2_StringDescriptor3);
			break;
		default:
			return -1;
		}
		break;
	default:
		return -1;
	}
	#undef response_descriptor

	if (sz_desc > setup_transfing_size)
		sz_desc = setup_transfing_size;
	setup_transfing_size = sz_desc;
	setup_transfing_point = desc;

	return 0;
}

int usb_standard_setup_request_handler(PXUSB_SETUP_REQ req)
{
	switch (req->bRequest) {
	case USB_GET_DESCRIPTOR:
		return usb_get_descriptor_handler(req->wValueH, req->wValueL);
	case USB_SET_ADDRESS:
		/* new address is addressed after device ACK */
		usb_new_address = req->wValueL;
		mark_ep0_nothing_upload();
		break;
	case USB_GET_CONFIGURATION:
		setup_transfing_size = sizeof(usb_configuration);
		setup_transfing_point = &usb_configuration;
		break;
	case USB_SET_CONFIGURATION:
		usb_configuration = req->wValueL;
		mark_ep0_nothing_upload();
		break;
	case USB_GET_INTERFACE:
		break;
	default:
		return -1;
	}

	return 0;
}

int usb_vendor_setup_request_handler(PXUSB_SETUP_REQ req)
{
	__xdata struct cdc_device *cdc = NULL;

	switch (req->bRequest) {
	case GET_LINE_CODING:
		if (req->wIndexL == 0)  /* interface 0 is cdc0 */
			cdc = &cdc0;
		else if (req->wIndexL == 2) /* interface 2 is cdc1 */
			cdc = &cdc1;

		if (!cdc)
			return -1;
		setup_transfing_point = cdc->line_coding;
		break;
	case SET_CONTROL_LINE_STATE:
	case SET_LINE_CODING:
		mark_ep0_nothing_upload();
		/* setting data packet defined in EP0 packet out */
		break;
	default:
		return -1;
	}

	return 0;
}

void usb_irq_setup_handler(uint8_t ep)
{
	PXUSB_SETUP_REQ req = (PXUSB_SETUP_REQ)Ep0Buffer;
	int len, failed = -1;

	if (ep == 0) {
		if(USB_RX_LEN == (sizeof(USB_SETUP_REQ))) {
			setup_transfing_size = ((uint16_t)req->wLengthH << 8) | req->wLengthL;
			memcpy(&usb_last_setup_req, req, sizeof(usb_last_setup_req));

			if ((req->bRequestType & USB_REQ_TYP_MASK ) == USB_REQ_TYP_STANDARD)
				failed = usb_standard_setup_request_handler(req);
			else
				failed = usb_vendor_setup_request_handler(req);
		}

		if (failed || (setup_transfing_size > 0 && !setup_transfing_point)) {
			/* STALL request */
			UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;
			return;
		}

		len = setup_transfing_size;
		if (len > DEFAULT_ENDP0_SIZE)
			len = DEFAULT_ENDP0_SIZE;

		memcpy(Ep0Buffer, setup_transfing_point, len);
		/* 最后一包数据小于EP0的最大长度, 不需要补充空包 */
		if (setup_transfing_size == 0 && len < DEFAULT_ENDP0_SIZE)
			setup_transfing_point = NULL;

		setup_transfing_point += len;
		setup_transfing_size -= len;

		UEP0_T_LEN = len;
		UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;
	}
}

void DeviceInterrupt(void) __interrupt (INT_NO_USB)                       //USB interrupt service routine, using register set 1
{
	if (UIF_TRANSFER) {
		switch (USB_INT_ST & MASK_UIS_TOKEN) {
		case UIS_TOKEN_IN:
			usb_irq_in_handler(USB_INT_ST & MASK_UIS_ENDP);
			break;
		case UIS_TOKEN_OUT:
			usb_irq_out_handler(USB_INT_ST & MASK_UIS_ENDP);
			break;
		case UIS_TOKEN_SETUP:
			usb_irq_setup_handler(USB_INT_ST & MASK_UIS_ENDP);
			break;
		}
		UIF_TRANSFER = 0; /* clear interrupt */
	} else if (UIF_BUS_RST) {
		usb_irq_reset_handler();
	} else if (UIF_SUSPEND) {
		usb_irq_suspend_handler();
	} else {
		USB_INT_FG = 0xFF;
	}
}

void uart0_isr(void) __interrupt (INT_NO_UART0)
{
	if (RI) {
		uart_fifo_put(&uart0, SBUF);
		RI = 0;
	}
}

void uart1_isr(void) __interrupt (INT_NO_UART1)
{
	if (U1RI) {
		uart_fifo_put(&uart1, SBUF1);
		U1RI = 0;
	}
}

void main()
{
	uint8_t t0 = 0, t1 = 0;

	CfgFsys( );
	mDelaymS(5);
	mInitSTDIO();
	UART1Setup();
	/* TI(发送中断标志位) is seted in mInitSTDIO */
	TI = 0;

	USBDeviceCfg();
	USBDeviceEndPointCfg();
	USBDeviceIntCfg();

	UEP0_T_LEN = 0;
	UEP1_T_LEN = 0;
	UEP2_T_LEN = 0;
	UEP3_T_LEN = 0;
	UEP4_T_LEN = 0;

	ES = 1;
	PS = 1;
	IE_UART1 = 1;
	IP_EX |= bIP_UART1;

	cdc_turn_off_led(&cdc0);
	cdc_turn_off_led(&cdc1);

	while(1) {
		if(usb_configuration) {
		#ifdef CDC_LOOPBACK
			if (!cdc0.upload_busy && cdc0.usb_rx_size > 0) {
				__xdata uint8_t *ep2_in = Ep2Buffer, *ep2_out = Ep2Buffer + MAX_PACKET_SIZE;

				memcpy(ep2_out, ep2_in, cdc0.usb_rx_size);

				/* cdc0: ready, continue recving */
				UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_R_RES | UEP_R_RES_ACK;

				UEP2_T_LEN = cdc0.usb_rx_size;
				UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK;
				cdc0.upload_busy = 1;
				cdc0.usb_rx_size = 0;

				cdc_turn_on_led(&cdc0);
			}

			if (!cdc1.upload_busy && cdc1.usb_rx_size > 0) {
				__xdata uint8_t *ep3_in = Ep3Buffer, *ep3_out = Ep3Buffer + MAX_PACKET_SIZE;

				memcpy(ep3_out, ep3_in, cdc1.usb_rx_size);

				/* cdc1: ready, continue recving */
				UEP3_CTRL = UEP3_CTRL & ~ MASK_UEP_R_RES | UEP_R_RES_ACK;

				UEP3_T_LEN = cdc1.usb_rx_size;
				UEP3_CTRL = UEP3_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK;
				cdc1.upload_busy = 1;
				cdc1.usb_rx_size = 0;

				cdc_turn_on_led(&cdc1);
			}
		#else
			int len0, len1;

			len0 = uart_fifo_length(cdc0.uart);
			len1 = uart_fifo_length(cdc1.uart);

			if (len0 > 0)
				t0++;
			if (len1 > 0)
				t1++;

			if (!cdc0.upload_busy && (t0 > 100 || len0 > UART_FIFO_SIZE >> 1)) {
				__xdata uint8_t *ep2_out = Ep2Buffer + MAX_PACKET_SIZE;
				int i;

				t0 = 0;
				for (i = 0; i < len0; i++) {
					uint8_t b;

					uart_fifo_get_without_check(cdc0.uart, &b);
					ep2_out[i] = b;
				}

				UEP2_T_LEN = len0;
				UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK;
				cdc0.upload_busy = 1;

				cdc_turn_on_led(&cdc0);
			}

			if (cdc0.usb_rx_size > 0) {
				__xdata uint8_t *ep2_in = Ep2Buffer;

				CH554UART0SendByte(ep2_in[cdc0.usb_fifo_idx++]);
				if (--cdc0.usb_rx_size == 0) {
					cdc0.usb_fifo_idx = 0;
					/* cdc0: ready, continue recving */
					UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_R_RES | UEP_R_RES_ACK;
				}

				cdc_turn_on_led(&cdc0);
			}

			if (!cdc1.upload_busy && (t1 > 100 || len1 > UART_FIFO_SIZE >> 1)) {
				__xdata uint8_t *ep3_out = Ep3Buffer + MAX_PACKET_SIZE;
				int i;

				t1 = 0;
				for (i = 0; i < len1; i++) {
					uint8_t b;

					uart_fifo_get_without_check(cdc1.uart, &b);
					ep3_out[i] = b;
				}

				UEP3_T_LEN = len1;
				UEP3_CTRL = UEP3_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK;
				cdc1.upload_busy = 1;

				cdc_turn_on_led(&cdc1);
			}

			if (cdc1.usb_rx_size > 0) {
				__xdata uint8_t *ep3_in = Ep3Buffer;

				CH554UART1SendByte(ep3_in[cdc1.usb_fifo_idx++]);
				if (--cdc1.usb_rx_size == 0) {
					cdc1.usb_fifo_idx = 0;
					/* cdc1: ready, continue recving */
					UEP3_CTRL = UEP3_CTRL & ~ MASK_UEP_R_RES | UEP_R_RES_ACK;
				}

				cdc_turn_on_led(&cdc1);
			}
		#endif
		}

		if (cdc0.led_timeout > 0 && --cdc0.led_timeout == 0)
			cdc_turn_off_led(&cdc0);
		if (cdc1.led_timeout > 0 && --cdc1.led_timeout == 0)
			cdc_turn_off_led(&cdc1);
	}
}
